package ch.areion.areionapp.periphery;

import ch.areion.areionapp.communication.Monitor;
import ch.areion.areionapp.core.Disconnectable;
import ch.areion.areionapp.io.BoxNumber;
import ch.areion.areionapp.io.IIO;
import ch.areion.common.message.Module;
import ch.areion.common.message.Type;
import ch.areion.common.message.Version;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.api.IOIO;
import ioio.lib.api.AnalogInput;

/**
 * Thread to control battery voltage.
 * @author Reto M?ller
 * @version 1.0
 */
public class BatteryControl implements Runnable, Disconnectable
{
	private Thread thread;
	private IIO io;
	private IOIO ioio;
	private AnalogInput analogIn;
	private float voltage; // [V]
	private static boolean die = false;
	private static final int IOIO_PORT = 46; // [ms]
	private static final float RESISTOR_1 = 27000f; // [Ohm]
	private static final float RESISTOR_2 = 10000f; // [Ohm]
	private static final float VOLTAGE_MIN = 3*3.3f; // [V]
	private static final float VOLTAGE_MAX = 3*4.2f; // [V]
	private static final float VOLTAGE_OFFSET = 0f; // [V]
	
	private static final long UPDATE_PERIODE = 10000; // [ms]
	

	/**
	 * Constructor of BatteryControl
	 * @param ioio_ makes it possible to connect with IOIO
	 * @exception ConnectionLostException
	 */
	public BatteryControl(IOIO ioio_, IIO io_) throws ConnectionLostException
	{
		ioio = ioio_;
		io = io_;
		analogIn = ioio.openAnalogInput(IOIO_PORT);
	}

	/**
	 * Starts the Thread.
	 */
	public void start()
	{
		if(thread == null){
			thread = new Thread(this);
			thread.start();
		}
	}
	
	/**
	 * Disconnects the BatteryControl from IOIO.
	 */
	public void disconnect() throws InterruptedException
	{
		die = true;
		thread.join();
		analogIn.close();
	}

	/**
	 * Battery voltage control loop. Checks voltage periodically and reports critical changes.
	 */
	public void run()
	{
		while(!die){
			try{
				voltage = (analogIn.getVoltage()*(RESISTOR_1+RESISTOR_2))/RESISTOR_2 + VOLTAGE_OFFSET;
				Monitor.getInstance().add(Version.V01, Type.INFO, Module.PERIPHERY, "Battery voltage ", String.format("%.3f %s", voltage, "V"));
				if(voltage <= VOLTAGE_MIN){
					io.setDisplayBoxnumber(BoxNumber.LOW_BATTERY);
					Monitor.getInstance().add(Version.V01, Type.WARNING, Module.PERIPHERY, "Battery voltage reaches critical level.");
				}else if(voltage > VOLTAGE_MAX){
					Monitor.getInstance().add(Version.V01, Type.WARNING, Module.PERIPHERY, "Battery voltage is anormaly high.");
				}
				Thread.sleep(UPDATE_PERIODE);
			}catch(ConnectionLostException c){
				//Monitor.getInstance().add(Version.V01, Type.ERROR, Module.PERIPHERY, c.getMessage()); No need to report, is reported in the main Controller class.
			}catch(InterruptedException e){
				Monitor.getInstance().add(Version.V01, Type.ERROR, Module.PERIPHERY, e.getMessage());
			}			
		}
	}
}
